import java.io.*;
import java.lang.Math;
class Attribute
{
	static private String [][]name = new String[41][55];
	static private int []num = new int[41];	static private boolean []ifContinuous = new boolean[41];
	static private double []maxContinuous = new double[41];
	static private double []minContinuous = new double[41];
	
	static public String [][]value;
	static private boolean []result;
	static public int validSize;
	static public int validSet[];
	static public Node root;
	public Attribute(int sizeData)
	{
		int i,j;
		root = new Node();
		for(i = 0;i < 41;i++)
		{
			maxContinuous[i] = 0;
			minContinuous[i] = 1000;
		}
		value = new String[sizeData][41];
		result = new boolean[sizeData];
		validSize = (new Float(sizeData * 0.4)).intValue();
		validSet = new int[validSize * 2];
		j = 0;
		for(i = 0;i < sizeData;i++)
		{
			if(i % 5 == 0 || (i-1)%5 == 0)
			{
				validSet[j] = i;
				j++;				
			}
		}
		validSize = j;
	}

	static public String getName(int i,int j)
	{
		return name[i][j];
	}
	
	static public void setName(int i,int j,String str)
	{
		name[i][j] = str;
	}
	
	static public int getNum(int i)
	{
		return num[i];
	}
	
	static public void setNum(int i,int j)
	{
		num[i] = j;
	}
	
	static public boolean getIfContinuous(int i)
	{
		return ifContinuous[i];
	}
	
	static public void setIfContinuous(int i,boolean j)
	{
		ifContinuous[i] = j;
	}
	
	static public double getMaxContinuous(int i)
	{
		return maxContinuous[i];
	}
	
	static public void setMaxContinuous(int i,double j)
	{
		maxContinuous[i] = j;
	}
	
	static public double getMinContinuous(int i)
	{
		return minContinuous[i];
	}	
	
	static public void setMinContinuous(int i,double j)
	{
		minContinuous[i] = j;
	}
		
	static public String getValue(int i,int j)
	{
		return value[i][j];
	}
	
	static public void setValue(int i,int j,String str)
	{
		value[i][j] = str;
	}
	
	static public boolean getResult(int i)
	{
		return result[i];
	}
	
	static public void setResult(int i,boolean j)
	{
		result[i] = j;
	}	

	public static double getGain(int setSize,int set[],int attributeName)
	{
		int i,j,k;
		double t;
		int setPositive = 0,setNegative = 0;
		double setEntropy;
		/**原示例集合中结果正负的多少*/
		for(i = 0;i < setSize;i++)
		{
			if(result[set[i]]) 
				setPositive++;
			else
				setNegative++;
		}
		/**原示例集合中Entropy的计算*/
		if(setPositive == 0 || setNegative == 0)
			setEntropy = 0;
		else
			setEntropy = (-(double)setPositive/setSize) * Math.log((double)setPositive/setSize)/Math.log(2) + (-(double)setNegative/setSize) * Math.log((double)setNegative/setSize)/Math.log(2);			
		double gain = setEntropy;
		/**用Continuous属性分裂原集合后子集合Entropy的计算*/
		if(ifContinuous[attributeName])
		{
			int []positive = new int[10];
			int []negative = new int[10];
			int []size = new int[10];
			double []entropy = new double[10];
			for(i = 0;i < setSize;i++)
			{
				if(!value[set[i]][attributeName].equals("?"))
				{
					/**判断取值在最小值与最大值具体区间，记录不同区间结果正负的多少*/
					t = (Double.parseDouble(value[set[i]][attributeName]) - minContinuous[attributeName])/(maxContinuous[attributeName] - minContinuous[attributeName])*10;
					k = (new Double(t)).intValue();
					if(k == 10) k = 9;
					if(result[set[i]])
						positive[k]++;
					else
						negative[k]++;
				}
			}
			for(i = 0;i < 10;i++)
			{
				/**总结结果正负的多少计算Entropy*/
				size[i] = positive[i] + negative[i];
				if(negative[i] == 0 || positive[i] == 0)
					entropy[i] = 0;
				else
					entropy[i] = (-(double)positive[i]/size[i]) * Math.log((double)positive[i]/size[i])/Math.log(2) + (-(double)negative[i]/size[i]) * Math.log((double)negative[i]/size[i])/Math.log(2);
				/**gain值的计算*/
				gain = gain - (double)size[i]/setSize * entropy[i];
			}
		}
		else
		{
			int numTemp = num[attributeName];
			int []positive = new int[numTemp];
			int []negative = new int[numTemp];
			int []size = new int[numTemp];
			double []entropy = new double[numTemp];		
			/**针对属性的每个取值*/
			for(i = 0;i < numTemp;i++)
			{
				/**针对集合中的每个元素*/
				for(j = 0;j < setSize;j++)
				{
					if(!value[set[j]][attributeName].equals("?"))
					{
						/**判断元素属性取值是否与i一致*/
						if(value[set[j]][attributeName].equals(name[attributeName][i]))
						{
							/**若一致，则记录此取值结果的正负*/
							if(result[set[j]])
								positive[i]++;
							else
								negative[i]++;
						}
					}
				}
				/**计算Entropy*/
				size[i] = positive[i] + negative[i];
				if(negative[i] == 0 || positive[i] == 0)
					entropy[i] = 0;
				else
					entropy[i] = (-(double)positive[i]/size[i]) * Math.log((double)positive[i]/size[i])/Math.log(2) + (-(double)negative[i]/size[i]) * Math.log((double)negative[i]/size[i])/Math.log(2);
				/**计算gain值*/
				gain = gain - (double)size[i]/setSize * entropy[i];
			}
		}
		return gain;
	}
	
	public static int getMaxGain(int setSize,int set[],boolean attributeSet[])
	{
		double maxGain = -1;
		double maxGainTemp = 0;
		int maxGainNum = -1;
		int i;
		/**对属性列表的每个属性对应的gain值进行比较大小，取最大的*/
		for(i = 0;i < 41;i++)
		{
			if(attributeSet[i])
			{
				maxGainTemp = getGain(setSize,set,i);
				if(maxGainTemp >= maxGain)
				{	
					maxGain = maxGainTemp;
					maxGainNum = i;
				}
			}
		}
		return maxGainNum;

	}
}
